package com.sgj.linkedlist;


/**
 * 单链表
 * @Author: Guoji Shen
 * @Date: 2021/8/3 9:18
 */
public class SingleLinkedListDemo {

    public static void main(String[] args) {
        // 测试
        // 先创建节点
        HeroNode hero1 = new HeroNode(1, "aa", "AAA");
        HeroNode hero2 = new HeroNode(2, "bb", "BBB");
        HeroNode hero3 = new HeroNode(3, "cc", "CCC");
        HeroNode hero4 = new HeroNode(4, "dd", "DDD");
        HeroNode hero5 = new HeroNode(3, "ff", "FFF");

        // 创建一个链表
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        // 加入数据
        // singleLinkedList.add(hero1);
        // singleLinkedList.add(hero2);
        // singleLinkedList.add(hero3);
        // singleLinkedList.add(hero4);

        singleLinkedList.addByNo(hero3);
        // singleLinkedList.addByNo(hero5);
        singleLinkedList.addByNo(hero2);
        singleLinkedList.addByNo(hero4);
        singleLinkedList.addByNo(hero1);

        // 显示
        System.out.println("====================修改前=====================");
        singleLinkedList.list();

        // 测试修改节点的代码
        HeroNode newHeroNode = new HeroNode(3, "gg", "GGG");
        singleLinkedList.update(newHeroNode);

        // 显示
        System.out.println("====================修改后=====================");
        singleLinkedList.list();

        // 测试删除节点的代码
        singleLinkedList.del(1);
        // singleLinkedList.del(2);
        // singleLinkedList.del(3);
        // singleLinkedList.del(4);

        // 显示
        System.out.println("====================删除后=====================");
        singleLinkedList.list();
    }

}

// 定义SingleLinkedList 管理我们的英雄
class SingleLinkedList {

    // 先初始化一个头节点，头节点一般不动，不存放具体的数据
    private HeroNode head = new HeroNode(0, "", "");

    // 获取头节点
    public HeroNode getHead() {
        return head;
    }

    // 添加节点到单向链表(不考虑排序)
    public void add (HeroNode heroNode) {

        // 因为head节点不能动，因此我们需要一个辅助变量temp
        HeroNode temp = head;
        // 遍历链表，找到最后
        while (true) {
            // 链表已经遍历结束
            if (temp.next == null) {
                break;
            }
            // 如果没有找到最后，将temp后移
            temp = temp.next;
        }
        // 当退出 while 循环时，temp就指向了链表的最后
        // 将最后这个节点的next指向新的节点
        temp.next = heroNode;
    }

    // 第二种方式在添加英雄时，根据排名将英雄插入到指定位置
    // 如果有这个排名，则添加失败，并给出提示
    public void addByNo(HeroNode heroNode) {

        // 因为head节点不能动，因此我们需要一个辅助变量temp来帮助我们找到添加的位置
        // 因为单链表，因为我们找的temo是位于添加位置的前一个节点，否则插入失败
        HeroNode temp = head;

        // 标识添加的编号是否存在，默认false
        boolean flag = false;

        while (true) {
            // 链表已经遍历结束
            if (temp.next == null) {
                break;
            }
            // 位置找到，就在temp的后面插入
            if (temp.next.no > heroNode.no) {
                break;
            }
            // 编号重复
            if (temp.next.no == heroNode.no) {
                flag = true;
                break;
            }
            // 后移
            temp = temp.next;
        }
        // 判断flag的值,如果为true，说明编号重复
        if (flag) {
            System.out.printf("准备插入的英雄编号[%d]已经存在，不能加入！！！\n", heroNode.no);
        } else {
            // 插入到链表中，temp 的后面
            heroNode.next = temp.next;
            temp.next = heroNode;
        }
    }

    // 修改节点的信息，根据no编号来修改，即no编号不能改
    public void update(HeroNode newHeroNode) {
        // 判断链表是否为空
        if (head.next == null) {
            System.out.println("链表为空！！！");
            return;
        }
        // 找到需要修改的节点，根据no编号
        // 定义一个辅助变量
        HeroNode temp = head.next;
        // 表示是否找到该节点
        boolean flag = false;
        while (true) {
            // 链表已经遍历结束
            if (temp == null) {
                break;
            }
            if (temp.no == newHeroNode.no) {
                // 找到
                flag = true;
                break;
            }
            temp = temp.next;
        }
        // 根据flag判断是否找到要修改的节点
        if (flag) {
            temp.name = newHeroNode.name;
            temp.nickname = newHeroNode.nickname;
        } else {
            // 没有找到
            System.out.printf("没有找到英雄编号为[%d]的英雄，不能修改！！！\n", newHeroNode.no);
        }
    }

    // 删除节点
    public void del(int no) {
        HeroNode temp = head;
        // 标识是否找到带删除节点
        boolean flag = false;
        while (true) {
            // 链表已经遍历结束
            if (temp.next == null) {
                break;
            }
            // 找到了待删除节点的前一个节点
            if (temp.next.no == no) {
                flag = true;
                break;
            }
            temp = temp.next;
        }
        // 根据flag判断是否找到待删除的节点
        if (flag) {
            temp.next = temp.next.next;
        } else {
            System.out.printf("没有找到英雄编号为[%d]的英雄，不能删除！！！\n", no);
        }
    }

    // 显示链表[遍历]
    public void list() {
        // 判断链表是否为空
        if (head.next == null) {
            System.out.println("链表为空！！！");
            return;
        }
        // 因为头节点不能动，因此我们需要一个辅助变量来遍历
        HeroNode temp = head.next;
        while (true) {
            // 判断是否到链表最后
            if (temp == null) {
                break;
            }
            // 输出节点信息
            System.out.println(temp);
            // 将temp后移
            temp = temp.next;
        }
    }
}

// 定义HeroNode，每个HeroNode对象就是一个节点
class HeroNode {

    /**
     * 排名
     */
    public int no;

    /**
     * 名称
     */
    public String name;

    /**
     * 昵称
     */
    public String nickname;

    /**
     * 指向下个节点
     */
    public HeroNode next;

    public HeroNode(int no, String name, String nickname) {
        this.no = no;
        this.name = name;
        this.nickname = nickname;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickname='" + nickname + '\'' +
                '}';
    }
}